#ifndef _RIGIDBODYPAYLOAD_H_
#define _RIGIDBODYPAYLOAD_H_

#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <SEPhysics/Entity/BaseShape.h>
#include <memory>
#include <SECore/Signal.h>

class btRigidBody;
class btCollisionShape;
class btMotionState;

namespace SEngine
{
    class RigidBodyPayload
    {
    public:
        enum CollisionFlags
        {
            CF_STATIC_OBJECT = 1,
            CF_KINEMATIC_OBJECT = 2,
            CF_NO_CONTACT_RESPONSE = 4,
            CF_CUSTOM_MATERIAL_CALLBACK = 8,  //this allows per-triangle material (friction/restitution)
            CF_CHARACTER_OBJECT = 16,
            CF_DISABLE_VISUALIZE_OBJECT = 32,          //disable debug drawing
            CF_DISABLE_SPU_COLLISION_PROCESSING = 64,  //disable parallel/SPU processing
            CF_HAS_CONTACT_STIFFNESS_DAMPING = 128,
            CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR = 256,
            CF_HAS_FRICTION_ANCHOR = 512,
            CF_HAS_COLLISION_SOUND_TRIGGER = 1024
        };

        struct BodySetting 
        {
            glm::mat4                   startTransform{1.0f};
            glm::vec3                   linearVelocity{0.0f};
            glm::vec3                   linearFactor{1.0f};
            glm::vec3                   angularVelocity{0.0f};
            glm::vec3                   angularFactor{1.0f};
            float                       friction{0.0f};
            float                       restitution{0.0f};
            float                       mass{1.0f};
            std::unique_ptr<BaseShape>  shape;
        };
    public:
        RigidBodyPayload();
        virtual ~RigidBodyPayload();

        virtual void OnUpdateTransform() = 0;

        btRigidBody * GetBody() { return m_body.get(); }
        glm::mat4 Transform();        
        void Transform(glm::mat4 & matrix);
        void ApplyImpulse(const glm::vec3 &impulse, const glm::vec3 & rel_pos);    
        void ApplyCentralImpulse(const glm::vec3 &impulse);
        void SetLinearVelocity(const glm::vec3 &v);
        glm::vec3 GetLinearVelocity();
        void SetLinearFactor(const glm::vec3 &v);
        void SetAngularVelocity(const glm::vec3 &v);
        glm::vec3 GetAngularVelocity();
        void SetAngularFactor(const glm::vec3 &v);
        void SetFriction(float friction);
        void SetRestitution(float rest);
        void SetCollisionFlags(int flags);
        int  GetCollisionFlags();
        void AddCollisionFlag(int flag);
        void RemoveCollisionFlag(int flag);
        void SetMass(float mass, glm::vec3 inertia);
        void SetMass(float mass);
        void SetKinematic(bool value);
        void SetTrigger(bool value);
        void SetShape(std::unique_ptr<BaseShape> && shape);
        BaseShape & GetShape() { return *m_shape; }
        void CreateBody(BodySetting & setting);
        void DestroyBody();

    public:
        Signal<btRigidBody*> SignalAddBody;
        Signal<btRigidBody*> SignalRemoveBody;
     
    private:
        std::unique_ptr<btRigidBody>    m_body;
        std::unique_ptr<btMotionState>  m_state;
        std::unique_ptr<BaseShape>      m_shape;
    };
} // namespace SEngine


#endif